import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import env from "/@/base/env";
import { message } from "ant-design-vue";
import { HttpStatusEnum, ResultCodeEnum } from "./httpEnum";
import getCodeMessage from "./getCodeMessage";
import { useI18n } from "/@/locales/useI18n";
import authCache from "/@/utils/cache/authCache";
import router from "/@/router";
import { useHomeStore } from "/@/stores/home";
import { RequestMethodEnum } from "/@/api/req/httpEnum";
import { Log } from "/@/base/log";
import { UserDetail } from "/@/api/home/user/models";

// const AuthenticationScheme = "Bearer";
const instance = axios.create();

Object.assign(instance.defaults, {
  headers: {
    "Content-Type": "application/json;charset=UTF-8",
  },
});
instance.interceptors.request.use(
  function (config) {
    const key = config.method === "get" ? "params" : "data";
    let target = config[key];
    if (!target) {
      target = config[key] = {};
    }
    // Log(config.url, "发送参数", target);
    return config;
  },
  function (error) {
    return Promise.reject(error);
  }
);
instance.interceptors.response.use(
  function (response) {
    const { data, config } = response;
    const key = config.method === "get" ? "params" : "data";
    let target = config[key];
    Log(config.url, "参数", target, "接收数据", data instanceof Blob ? "[blob data]" : data);
    return response;
  },
  function (error) {
    const response = error.response;
    if (response) {
      const { config, data } = response;
      const key = config.method === "get" ? "params" : "data";
      let target = config[key];
      Log(config.url, "参数", target, "接收错误", data);
    } else {
      Log("接收错误", error);
    }
    return Promise.reject(error);
  }
);
export interface ResponseData<T = any> {
  code: number;
  data: T;
  rows: T;
  msg?: string | null;
  errorMsg?: string | null;
  extra?: any;
  isSuccess?: boolean;
  path?: string | null;
  timestamp?: number;
  token: string;
  user: UserDetail;
  fileName: string;
  url: string;
  checkedKeys: number[];
}
export interface RequsetOptons {
  //注意当采用默认的失败或异常处理时 最后会resolve(null)
  //当result code不为0或200时，是否采用默认的失败处理
  useDefaultFailHandle?: boolean;
  //当httpstatus不为200时，是否采用默认的异常处理
  useDefaultErrHandle?: boolean;
  //是否需要token
  withToken?: boolean;
  //是否强制使用mock url
  mock?: boolean;
  //是否使用全局loading
  useGlobalLoading?: boolean;
  //是否将response全部返回，默认是返回response的data
  isReturnResponse?: boolean;
}
interface ReqError {
  response: AxiosResponse;
  request: any;
}

export function getAuthHeaderInfo(isAutoRedirect?: boolean) {
  const token = authCache.getToken();
  if (!token) {
    if (isAutoRedirect) {
      router.push("/login");
    }
    return;
  }
  //: `${AuthenticationScheme} ${token}`
  return {
    Authorization: token,
  };
}

function dealErrorResponse(response: AxiosResponse<ResponseData<any>>): ResponseData<any> {
  if (response) {
    if (response.data) {
      const codeMsg = getCodeMessage(response.data.code);
      if (codeMsg) {
        response.data.msg = codeMsg;
      }
    }
  }
  return (
    response.data || {
      code: response.status,
      msg: response.statusText,
    }
  );
}
function hideLoading() {
  const homeStore = useHomeStore();
  homeStore.toggleLoading({
    loading: false,
  });
}

function getReqOptions(options?: RequsetOptons) {
  return Object.assign(
    {
      useDefaultFailHandle: true,
      useDefaultErrHandle: true,
      withToken: true,
      mock: false,
      useGlobalLoading: true,
    },
    options || {}
  );
}
function doReq<T>(config: AxiosRequestConfig, options: RequsetOptons) {
  if (options.withToken) {
    if (!config.headers) {
      config.headers = {};
    }
    const authHeader = getAuthHeaderInfo(true);
    if (!authHeader) {
      return Promise.reject(null);
    }
    Object.assign(config.headers, authHeader);
  }
  if (options.mock) {
    config.baseURL = env.mockBaseUrl;
  }
  const serverIp = authCache.getServerIp();
  if (serverIp === "0.0.0.0") {
    config.baseURL = env.baseUrl;
  } else if (serverIp) {
    config.baseURL = `http://${serverIp}/api/`;
  }
  if (options.useGlobalLoading) {
    const homeStore = useHomeStore();
    homeStore.toggleLoading({
      loading: true,
    });
  }
  return instance
    .request<T>(config)
    .then((resp) => {
      hideLoading();
      if (resp.status === HttpStatusEnum.SUCCESS) {
        return resp.data;
      }
      throw { code: resp.status, msg: resp.statusText };
    })
    .catch((err: ReqError) => {
      hideLoading();
      const { t } = useI18n();
      const { response } = err;
      const data = response
        ? dealErrorResponse(response)
        : {
            msg: null,
            code: null,
          };
      if (options?.useDefaultErrHandle) {
        //默认异常处理
        message.error(data.msg || t("common.loadError"));
        if (data.code === ResultCodeEnum.JWT_NOT_LOGIN || data.code === ResultCodeEnum.JWT_TOKEN_EXPIRED) {
          router.push("/login");
        }
        return null;
      } else {
        //自定义异常处理
        throw data;
      }
    });
}

function doReqWithResponse(config: AxiosRequestConfig, options?: RequsetOptons) {
  options = getReqOptions(options);
  return doReq<ResponseData | Blob>(config, options).then((data) => {
    if (data) {
      if (data instanceof Blob) {
        return data;
      }
      if (data.code === ResultCodeEnum.SUCCESS || data.code === ResultCodeEnum.SUCCESS200) {
        return data;
      } else {
        const err = handleError(data, options);
        if (err) {
          throw err;
        }
        return null;
      }
    }
    return null;
  });
}

function doReqWithData<T>(config: AxiosRequestConfig, options?: RequsetOptons) {
  options = getReqOptions(options);
  return doReq<ResponseData<T>>(config, options).then((data) => {
    if (data) {
      if (data.code === ResultCodeEnum.SUCCESS || data.code === ResultCodeEnum.SUCCESS200) {
        return data.data || data.rows || undefined;
      } else {
        const err = handleError(data, options);
        if (err) {
          throw err;
        }
        return null;
      }
    }
    return null;
  });
}

function handleError(data: ResponseData, options?: RequsetOptons) {
  if (data.code === ResultCodeEnum.UNAUTHORIZED || data.code === ResultCodeEnum.JWT_NOT_LOGIN) {
    //token过期或未登录
    router.push("/login");
    if (data.code === ResultCodeEnum.JWT_NOT_LOGIN) {
      message.error(getCodeMessage(ResultCodeEnum.JWT_NOT_LOGIN) as string);
    }
    return null;
  } else {
    const codeMsg = getCodeMessage(data.code);
    if (codeMsg) {
      data.msg = codeMsg;
    }
    if (options?.useDefaultFailHandle) {
      const { t } = useI18n();
      message[codeMsg ? "info" : "error"](data.msg || t("common.loadError"));
      return null;
    } else {
      return data;
    }
  }
}

const req = {
  get<T>(config: AxiosRequestConfig, options?: RequsetOptons) {
    config.method = RequestMethodEnum.GET;
    return doReqWithData<T>(config, options);
  },
  post<T>(config: AxiosRequestConfig, options?: RequsetOptons) {
    config.method = RequestMethodEnum.POST;
    return doReqWithData<T>(config, options);
  },
  delete<T>(config: AxiosRequestConfig, options?: RequsetOptons) {
    config.method = RequestMethodEnum.DELETE;
    return doReqWithData<T>(config, options);
  },
  put<T>(config: AxiosRequestConfig, options?: RequsetOptons) {
    config.method = RequestMethodEnum.PUT;
    return doReqWithData<T>(config, options);
  },
  getResponse(config: AxiosRequestConfig, options?: RequsetOptons) {
    config.method = RequestMethodEnum.GET;
    return doReqWithResponse(config, options);
  },
  commonPostResponse<K = Record<string, any>>(url: string, data?: K | null, options?: RequsetOptons) {
    const config: AxiosRequestConfig = {
      url,
      data,
      method: RequestMethodEnum.POST,
    };
    return doReqWithResponse(config, options) as Promise<ResponseData>;
  },
  commonGetResponse<K = Record<string, any>>(url: string, params?: K | null, options?: RequsetOptons) {
    const config: AxiosRequestConfig = {
      url,
      params,
      method: RequestMethodEnum.GET,
    };
    return doReqWithResponse(config, options) as Promise<ResponseData>;
  },
  commonPutResponse<K = Record<string, any>>(url: string, data?: K | null, options?: RequsetOptons) {
    const config: AxiosRequestConfig = {
      url,
      data,
      method: RequestMethodEnum.PUT,
    };
    return doReqWithResponse(config, options) as Promise<ResponseData>;
  },
  commonGet<T, K = Record<string, any>>(url: string, params?: K | null, options?: RequsetOptons) {
    const config: AxiosRequestConfig = {
      url,
      params,
      method: RequestMethodEnum.GET,
    };
    return doReqWithData<T>(config, options);
  },
  commonPost<T, K = Record<string, any>>(url: string, data?: K | null, options?: RequsetOptons) {
    const config: AxiosRequestConfig = {
      url,
      data,
      method: RequestMethodEnum.POST,
    };
    return doReqWithData<T>(config, options);
  },
  commonExport<T>(url: string, data?: T | null, options?: RequsetOptons) {
    const config: AxiosRequestConfig = {
      url,
      data,
      responseType: "blob",
      method: RequestMethodEnum.POST,
    };
    return doReqWithResponse(config, options) as Promise<Blob>;
  },
};
export default req;
